package org.xtext.runtime.eis;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

import org.xtext.runtime.formula.Predicate;
import org.xtext.runtime.interpreter.ASTRAClass;
import org.xtext.runtime.interpreter.ASTRAClassNotFoundException;
import org.xtext.runtime.interpreter.Agent;
import org.xtext.runtime.interpreter.DuplicateAgentNameException;
import org.xtext.runtime.term.ITerm;
import org.xtext.runtime.term.Term;

public class EISBasicLoader {
	public static void main(String[] args) {
		if (args.length == 0) {
			System.out.println("This loader takes 1 argument: the name of the EIS configuration file to be loaded.");
		}
		
		String id = args[0];
		
		Properties properties = new Properties();
		try {
			FileInputStream in = new FileInputStream(new File(".eis", id));
			properties.load(in);
			in.close();
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		
		EISService service = EISService.getService(id, properties.getProperty("jar"));

		String[] entities = properties.getProperty("entities").split(",");
		Agent[] agents = new Agent[entities.length];
		for (int i=0;i<entities.length; i++) {
			try {
				agents[i] = ASTRAClass.forName(properties.getProperty(entities[i])).newInstance(entities[i]);
				service.registerAgent(agents[i]);
				service.associateEntity(agents[i], entities[i]);
				agents[i].initialize(new Predicate("service", 
						new ITerm[] { Term.newInstance(id) }
				));
			} catch (ASTRAClassNotFoundException e1) {
				e1.printStackTrace();
			} catch (DuplicateAgentNameException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}
		service.eisStart();
		
		System.out.println("Sequential Execution of " + agents.length + " agents.");

		Executor[] e = new Executor[4];
		for (int i=0;i<e.length;i++) {
			e[i] = new Executor();
		}
		for (int j = 0; j < agents.length; j++) {
			e[j%e.length].addAgent(agents[j]);
		}
		for (int i=0;i<e.length;i++) {
			new Thread(e[i]).start();
		}
	}
	
}

class Executor implements Runnable {
	List<Agent> agents = new LinkedList<Agent>();
	public void run() {
		while (true) {
			for (Agent a : agents) {
				a.execute();
			}
		}
	}
	
	public void addAgent(Agent a) {
		agents.add(a);
	}
}
